using System;
using System.Collections;
using System.Collections.Generic;
using System.Configuration.Install;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Security.Permissions;
using System.Text;

namespace EntLibContrib.Logging.Install
{
	/// <summary>
	/// Logging Installer Class
	/// </summary>
    public class LoggingInstaller : Installer
    {
        private string configPath_;

		/// <summary>
		/// Initializes a new instance of the <see cref="LoggingInstaller"/> class.
		/// </summary>
		/// <param name="configPath">The config path.</param>
        public LoggingInstaller(string configPath)
        {
            if (configPath == null)
            {
                throw new ArgumentNullException("configPath");
            }

            if (!File.Exists(configPath))
            {
                throw new ArgumentException("The configuration file was not found.", "configPath");
            }

            this.configPath_ = configPath;
        }

		/// <summary>
		/// When overridden in a derived class, performs the installation.
		/// </summary>
		/// <param name="stateSaver">An <see cref="T:System.Collections.IDictionary"/> used to save information needed to perform a commit, rollback, or uninstall operation.</param>
		/// <exception cref="T:System.ArgumentException">The <paramref name="stateSaver"/> parameter is null. </exception>
		/// <exception cref="T:System.Exception">An exception occurred in the <see cref="E:System.Configuration.Install.Installer.BeforeInstall"/> event handler of one of the installers in the collection.-or- An exception occurred in the <see cref="E:System.Configuration.Install.Installer.AfterInstall"/> event handler of one of the installers in the collection. </exception>
        public override void Install(IDictionary stateSaver)
        {
            this.AddEventLogInstallers();
            base.Install(stateSaver);
        }

		/// <summary>
		/// When overridden in a derived class, removes an installation.
		/// </summary>
		/// <param name="savedState">An <see cref="T:System.Collections.IDictionary"/> that contains the state of the computer after the installation was complete.</param>
		/// <exception cref="T:System.ArgumentException">The saved-state <see cref="T:System.Collections.IDictionary"/> might have been corrupted. </exception>
		/// <exception cref="T:System.Configuration.Install.InstallException">An exception occurred while uninstalling. This exception is ignored and the uninstall continues. However, the application might not be fully uninstalled after the uninstallation completes. </exception>
        public override void Uninstall(IDictionary savedState)
        {
            this.AddEventLogInstallers();
            base.Uninstall(savedState);
        }

		/// <summary>
		/// Adds the event log installers.
		/// </summary>
        [SecurityPermission(SecurityAction.Demand, ControlAppDomain = true)]
        protected virtual void AddEventLogInstallers()
        {
            Assembly currentAssembly = Assembly.GetExecutingAssembly();

            AppDomainSetup domainSetup = new AppDomainSetup();
            domainSetup.ApplicationBase = Path.GetDirectoryName(this.configPath_);
            domainSetup.ConfigurationFile = this.configPath_;

            AppDomain targetAppDomain = AppDomain.CreateDomain(
                "TargetApplicationDomain", null, domainSetup);

            AppDomain.CurrentDomain.AssemblyResolve +=
                delegate(object sender, ResolveEventArgs e)
                {
                    if (e.Name == currentAssembly.FullName)
                    {
                        return currentAssembly;
                    }
                    throw new InvalidOperationException(string.Format(
                        CultureInfo.CurrentCulture,
                        "No assembly resolution logic was defined for {0}",
                        e.Name));
                };

            LoggingConfigurationLoader configLoader =
                (LoggingConfigurationLoader)targetAppDomain.CreateInstanceAndUnwrap(
                typeof(LoggingConfigurationLoader).Assembly.FullName,
                typeof(LoggingConfigurationLoader).FullName);

            foreach (EventLogConfiguration elc in configLoader.EventLogs)
            {
                EventLogInstaller logInstaller = new EventLogInstaller();
                logInstaller.Log = elc.Log;
                logInstaller.Source = elc.Source;
                this.Installers.Add(logInstaller);
            }

            AppDomain.Unload(targetAppDomain);
        }
    }
}
